/*
 * Copyright 2010-2012 Susanta Tewari. <freecode4susant@users.sourceforge.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package genomemap.netbeans.jobs1.map;

import cef.pui.EventConstructionException;
import cef.pui.pob.Builder;
import commons.nb.data.gui.properties.DataPropertys;
import commons.nb.jobs.Job;
import commons.nb.jobs.gui.JobsGUIUtil;
import commons.nb.jobs.properties.*;
import genomemap.cef.command.DrawAlignmentMap_Cmd;
import genomemap.cef.command.listener.DrawAlignmentMap_OC;
import genomemap.cef.pui.DrawAlignmentMap_EvtImpl;
import genomemap.map.AlignmentMap;
import genomemap.map.GenomeMap;
import genomemap.nb.jobs.properties.editors.PropertyEditors_Gen;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import static commons.core.ValueTypes.StringList;

/**
 * @author Susanta Tewari
 */
public class DrawAlignmentMapJob extends Job<DrawAlignmentMap_EvtImpl> {

    private BuilderProperty list1_1_prop;
    private BuilderProperty list1_2_prop;
    private final String keyPrefix1 = "commons.builder.StringList2.list1";
    private final String keyPrefix2 = "commons.builder.StringList2.list2";

    public DrawAlignmentMapJob() {

        setName("alignment-map");
        setDisplayName("Alignment Map");
        setShortDescription("Draws alignment map to compare multiple maps");
        addComboProperty(AlignMap_CREATE_DISPLAY());


        // attach listeners
        addCommandOutputListener(JobsGUIUtil.makeEmbeddable(new DrawAlignmentMap_OC()));
    }

    @Override
    protected boolean needsOutputWindow() {
        return false;
    }

    @Override
    public boolean shouldRun() {

        final Builder b1 = list1_1_prop.getValue();
        final Builder b2 = list1_2_prop.getValue();

        if (b1 == b2) {

            final String message = "" + //J-
                    "<html>" +
                    "The chosen maps are the same." +
                    "</html>" +
                    "";//J+

            final NotifyDescriptor nd = new NotifyDescriptor(message, "Same Maps chosen",
                                            NotifyDescriptor.OK_CANCEL_OPTION,
                                            NotifyDescriptor.INFORMATION_MESSAGE, null, null);

            DialogDisplayer.getDefault().notify(nd);

            return false;
        }

        final StringList labels1   = (StringList) b1.build();
        final StringList labels2   = (StringList) b2.build();
        final List<GenomeMap> maps = new ArrayList<>(2);

        maps.add(new GenomeMap(labels1.getData(), "map1"));
        maps.add(new GenomeMap(labels2.getData(), "map2"));

        final Collection<String> commonSet = AlignmentMap.commonsSet(maps);
        final boolean empty                = commonSet.isEmpty();

        if (empty) {

            final String message = "" + //J-
                    "<html>" +
                    "The chosen maps do not have any elements in common." +
                    "</html>" +
                    "";//J+

            final NotifyDescriptor nd = new NotifyDescriptor(message, "Common Set Empty",
                                            NotifyDescriptor.OK_CANCEL_OPTION,
                                            NotifyDescriptor.INFORMATION_MESSAGE, null, null);

            DialogDisplayer.getDefault().notify(nd);
        }

        return !empty;
    }

    @Override
    protected DrawAlignmentMap_EvtImpl createEvent() throws EventConstructionException {

        final Builder b1 = list1_1_prop.getValue();
        Builder b2       = list1_2_prop.getValue();

        if (b1 == b2) b2 = b1.clone();

        b1.setPrefix(keyPrefix1);
        b2.setPrefix(keyPrefix2);
        list1_1_prop.addSilentProperty(keyPrefix1 + ".delegate", b1.getBuilderString());
        list1_2_prop.addSilentProperty(keyPrefix2 + ".delegate", b2.getBuilderString());

        return new DrawAlignmentMap_EvtImpl(getProperties());
    }

    @Override
    protected DrawAlignmentMap_Cmd createCommand(final DrawAlignmentMap_EvtImpl event) {
        return new DrawAlignmentMap_Cmd(event);
    }

    private ComboProperty AlignMap_CREATE_DISPLAY() {

        final String keyPrefix = "commons.builder.StringList2";


        // dependent props: list1_1_prop, list1_1_prop, list2_prop
        list1_1_prop = DataPropertys.StringList_BUILDERS();
        list1_2_prop = DataPropertys.StringList_BUILDERS();

        final BuilderProperty list2_prop = DataPropertys.StringList2_BUILDERS();

        list1_1_prop.setName("stringlist1-list1_1_prop");
        list1_1_prop.setName("stringlist1-list1_2_prop");
        list2_prop.setName("stringlist2-list2_prop");
        list1_1_prop.setKeyPrefix(keyPrefix1);
        list1_2_prop.setKeyPrefix(keyPrefix2);
        list2_prop.setKeyPrefix(keyPrefix);
        list1_1_prop.addSilentProperty(keyPrefix + ".delegate",
                                       "cef.pui.pob.Builders$StringList2_Delegates");
        list1_1_prop.addSilentProperty(keyPrefix1 + ".delegate",
                                       "cef.pui.pob.Builders$StringList_File");
        list1_2_prop.addSilentProperty(keyPrefix2 + ".delegate",
                                       "cef.pui.pob.Builders$StringList_File");


        // controller prop
        final Property<String> controller_prop =
            Propertys.ofString("aMap-createDisplay-controller", "Choose operation type",
                               "Choose between creating or displaying an alignment map",
                               PropertySets.DATA, "", "alignmap-create");

        list2_prop.setActive(false);
        controller_prop.setPropEditorClass(PropertyEditors_Gen.AlignMap_CREATE_DISPLAY.class);
        controller_prop.addDependent(list1_1_prop);
        controller_prop.addDependent(list1_2_prop);
        controller_prop.addDependent(list2_prop);
        controller_prop.setPropertyChangeListenerDelegate(new PropertyChangeListener() {

            @Override
            public void propertyChange(PropertyChangeEvent evt) {

                final String value = controller_prop.getValue();

                switch (value) {

                    case "alignmap-create" :
                        list1_1_prop.setActive(true);
                        list1_2_prop.setActive(true);
                        list2_prop.setActive(false);

                        break;

                    case "alignmap-display" :
                        list2_prop.setActive(true);
                        list1_1_prop.setActive(false);
                        list1_2_prop.setActive(false);

                        break;

                    default :
                        throw new IllegalStateException();
                }
            }

        });


        // prepare combo
        final ComboPropertyImpl combo_prop = new ComboPropertyImpl(controller_prop);

        combo_prop.addComboProperty(list1_1_prop);
        combo_prop.addComboProperty(list1_2_prop);
        combo_prop.addComboProperty(list2_prop);

        return combo_prop;
    }

    @Override
    public boolean isCancellable() {
        return DrawAlignmentMap_Cmd.isCancellable();
    }

    @Override
    public Class<DrawAlignmentMap_EvtImpl> getEventImplType() {
        return DrawAlignmentMap_EvtImpl.class;
    }
}
